// created on 16/08/2004 at 22:22

using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Collections;
using System.Text;



namespace Orz.LogManager 
{
	public enum WildcardOptions
	{
		None,
		Simple,
		RegularExpressions
	}
	
		
	public class Finder
	{
		protected string sPattern_i = "";
		protected bool bMatchCase_i = false;
		protected bool bWholeWordsOnly_i = false;
		protected bool bWrapSearches_i = true;
		protected bool bSearchForwards_i = true;
		protected WildcardOptions wildcards_i = WildcardOptions.None;
		
		protected IList previousPatterns_i = new System.Collections.ArrayList();
		
		public bool Find (RichTextBox rtb_p)
		{
		    AddToPreviousPatterns();
		    
			if (WildcardOptions.None == Wildcards)
			{
				return SimpleFind (rtb_p);
			}
			else
			{
				return RegExpFind (rtb_p);
			}			
		}
		
		
		
		public string Pattern
		{
			get { return sPattern_i;  }
			set { sPattern_i = value; }
		}
		
		
		public bool MatchCase
		{
			get { return bMatchCase_i;  }
			set { bMatchCase_i = value; }
		}
		
		
		public bool WholeWordsOnly
		{
			get { return bWholeWordsOnly_i;  }
			set { bWholeWordsOnly_i = value; }
		}
		
		
		public bool WrapSearches
		{
			get { return bWrapSearches_i;  }
			set { bWrapSearches_i = value; }
		}
		
		
		public bool SearchForwards
		{
			get { return bSearchForwards_i;  }
			set { bSearchForwards_i = value; }
		}
		
		
		public WildcardOptions Wildcards
		{
			get { return wildcards_i;  }
			set { wildcards_i = value; }
		}
		
		
		public IList PreviousPatterns
		{
		    get { return previousPatterns_i; }
		}
		
		
		public override string ToString()
		{
		    StringBuilder sb = new StringBuilder();
		    sb.Append ("Finder: Pattern=<" + Pattern + ">, ");
		    sb.Append ("MatchCase=<" + MatchCase + ">, ");
		    sb.Append ("WholeWordsOnly=<" + WholeWordsOnly + ">, ");
		    sb.Append ("WrapSearches=<" + WrapSearches + ">, ");
		    sb.Append ("SearchForwards=<" + SearchForwards + ">, ");
		    sb.Append ("Wildcards=<" + Wildcards + ">");
		    
		    for (int i=0; i<PreviousPatterns.Count; i++)
		    {
		        string sPattern = (string) PreviousPatterns[i];
		        sb.Append (", PreviousPattern" + i + "=<" + sPattern + ">");
		    }
		    
		    return sb.ToString();
		}
		
		
		private bool SimpleFind (RichTextBox rtb_p)
		{
			int iStartIndex = 0;
			int iEndIndex = rtb_p.Text.Length;
			
			RichTextBoxFinds options = RichTextBoxFinds.None;			
			if (WholeWordsOnly) options |= RichTextBoxFinds.WholeWord;
			if (MatchCase)      options |= RichTextBoxFinds.MatchCase;
			
			if (SearchForwards)
			{
				iStartIndex = rtb_p.SelectionStart + rtb_p.SelectionLength;				
			}
			else
			{				
				iEndIndex = rtb_p.SelectionStart;
				options |= RichTextBoxFinds.Reverse;
			}
						
			int iResult = rtb_p.Find (Pattern, iStartIndex, iEndIndex, options);

			if (-1 == iResult  &&  WrapSearches)
			{
				iResult = rtb_p.Find (Pattern, 0, rtb_p.Text.Length,  options);				
			}
			
			return (-1 != iResult);
		}
		
		
		
		
		private bool RegExpFind (RichTextBox rtb_p)
		{
			int iStartIndex = 0;
			int iEndIndex = rtb_p.Text.Length;
			
			if (SearchForwards)
			{
				iStartIndex = rtb_p.SelectionStart + rtb_p.SelectionLength;				
			}
			else
			{				
				iEndIndex = rtb_p.SelectionStart;				
			}
			
			string sTextToSearch = rtb_p.Text.Substring (iStartIndex, iEndIndex - iStartIndex);
			
			Regex re = CreateRegularExpression();
			MatchCollection matches = re.Matches (sTextToSearch);
			
			if (0 == matches.Count  &&  WrapSearches)
			{
				iStartIndex = 0;
				matches = re.Matches (rtb_p.Text);
			}
			
			if (0 == matches.Count) 
			{
				return false;
			}
			else if (SearchForwards)
			{
				SelectMatch (iStartIndex, matches[0], rtb_p);
			}
			else
			{
				SelectMatch (iStartIndex, matches[matches.Count - 1], rtb_p);
			}
			
			return true;				
		}
		
		
		
		
		
		
		protected Regex CreateRegularExpression ()
		{
			string sPattern = Pattern;
		    
		    if (WildcardOptions.Simple == Wildcards)
		    {
		        sPattern = WildcardsToRegExpPattern (sPattern);
		    }
		    
		    RegexOptions options = RegexOptions.Multiline;			
			if (! MatchCase) options |= RegexOptions.IgnoreCase;
						
			if (WholeWordsOnly) sPattern = "\\b" + sPattern + "\\b";
			
			return new Regex(sPattern, options);			
		}
		
		
		
		
		private void SelectMatch (int iStartIndex_p, Match match_p, RichTextBox rtb_p)
		{
			rtb_p.Select (match_p.Index + iStartIndex_p, match_p.Length);
		}
		
		
		
		protected string WildcardsToRegExpPattern (string sPattern_p)
		{
			string sNewPattern = "";
			bool bEscaped = false;
			    
			for (int i=0; i<sPattern_p.Length; i++)
			{
				char c = sPattern_p[i];
				
				if (bEscaped)
				{
					if (IsSpecialChar (c))
					{
						sNewPattern += @"\" + c;						
					}
					else
					{
						sNewPattern += @"\\" + c;
					}
					
					bEscaped = false;
				}
				else
				{
					if ('\\' == c)
					{
					    bEscaped = true;
					}
					else 
				    {
				        sNewPattern += SpecialCharToRegExp (c);
					}
				}
			}
			
			if (bEscaped) sNewPattern += @"\\";
			    
			return sNewPattern;
		}
		
		
		
		private bool IsSpecialChar (char c_p)
		{
			string sSpecialChars = @"\*?#";
			
			return (-1 != sSpecialChars.IndexOf (c_p));
		}
		
		
		
		private string SpecialCharToRegExp (char c_p)
		{
		    string sNormalSpecials = @"\[]()+.$^";
		    
		    switch (c_p)
		    {
    	        case '*':    return ".*";    	      
    	        case '?':    return ".?";    	        
    	        case '#':    return "\\d";    	        
		    }
		    
            if (-1 == sNormalSpecials.IndexOf (c_p))
            {
                return c_p.ToString();
            }
            else
            {
                return "\\" + c_p;            
		    }
		}
		
		
		protected void AddToPreviousPatterns()
		{
		    if (0 != previousPatterns_i.Count)
		    {
		        string sLastPattern = (string) previousPatterns_i[previousPatterns_i.Count-1];		        
		        if (sLastPattern.Equals (Pattern)) return;
		    }
		    
		    previousPatterns_i.Add (Pattern);
		}
		
		
		
		
		
		
		private void TestWildcards ()
		{
		    // "one" 		"one"        "one"
			// "o*e"		"o.*e"       "oe" "oxe" "oxxxxxe"
			// "o\f"		"o\\f"       "o\f"
			// "o\*f"		"o\*f"       "o*f"
			// "o\\f"		"o\\f"       "o\f"
			// "o\\*f"		"o\\.*f"     "o\f" "o\xf" "o\xxxxxf"
		    // "o\"         "o\\"        "o\"		    
		    // "o[f"        "o\[f"       "o[f"
		    
		    TestSingleWildcard (@"one", @"one");
		    TestSingleWildcard (@"o*e", @"o.*e");
		    TestSingleWildcard (@"o\f", @"o\\f");
		    TestSingleWildcard (@"o\*f", @"o\*f");
		    TestSingleWildcard (@"o\\f", @"o\\f");
		    TestSingleWildcard (@"o\\*f", @"o\\.*f");
		    TestSingleWildcard (@"o\", @"o\\");
		    TestSingleWildcard (@"o[f", @"o\[f");
		}
		
		
		
		private void TestSingleWildcard (string sOriginalPattern_p, string sExpected_p)
		{		    
		    string sNewPattern = this.WildcardsToRegExpPattern (sOriginalPattern_p);		    
		    //Assertion.AssertEquals ("Mismatch!", sExpected_p, sNewPattern);
		}
		
		
	}
}
